package user

import (
	"fmt"
	"context"
	"github.com/google/uuid"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf-demo-user/v2/api/web/v1"
	"github.com/gogf/gf-demo-user/v2/internal/dao"
	"github.com/gogf/gf-demo-user/v2/internal/model"
	"github.com/gogf/gf-demo-user/v2/internal/model/do"
	"github.com/gogf/gf-demo-user/v2/internal/model/entity"
	"github.com/gogf/gf-demo-user/v2/internal/service"
)

type (
	sUser struct{}
)

func init() {
	service.RegisterUser(New())
}

func New() service.IUser {
	return &sUser{}
}

// Create creates user account.
func (s *sUser) Create(ctx context.Context, in model.UserCreateInput) (err error) {
	var (
		available bool
	)
	// Email checks.
	available, err = s.IsPassportAvailable(ctx, in.Email)
	if err != nil {
		return err
	}
	if !available {
		return gerror.Newf(`Email "%s" is already token by others`, in.Email)
	}
	return dao.Account.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		_, err = dao.Account.Ctx(ctx).Data(do.Account{
			Email: in.Email,
			Password: in.Password,
		}).Insert()
		return err
	})
}

// Create creates company.
func (s *sUser) CompanyPost(ctx context.Context, in *v1.CompanyPostReq) (err error) {
	account := service.Session().GetUser(ctx)
	fmt.Println(account)
	if account == nil {
		return gerror.New(`Please login first`)
	}
	return dao.Account.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		_, err = dao.Company.Ctx(ctx).Data(g.Map{
			"name" : in.Name,
			"description" : in.Description,
			"industry" : in.Industry,
			"tag" : in.Tag,
			"address" : in.Address,
			"website" : in.Website,
			"city" : in.City,
			"size" : in.Size,
			"contact" : in.Contact,
			"account" : account.Id,
			"logo" : in.Logo,
		}).Insert()
		return err
	})
}

// Create creates company.
func (s *sUser) CompanyMeUp(ctx context.Context, in *v1.CompanyMeUpReq) (err error) {
	account := service.Session().GetUser(ctx)
	fmt.Println(account)
	if account == nil {
		return gerror.New(`Please login first`)
	}
	return dao.Account.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		_, err = dao.Company.Ctx(ctx).Data(g.Map{
			"name" : in.Name,
			"description" : in.Description,
			"industry" : in.Industry,
			"tag" : in.Tag,
			"address" : in.Address,
			"website" : in.Website,
			"city" : in.City,
			"size" : in.Size,
			"contact" : in.Contact,
			"logo" : in.Logo,
		}).Where("id", account.Id).Update()
		return err
	})
}
// update creates company.
func (s *sUser) CompanyUp(ctx context.Context, in *v1.CompanyUpReq) (err error) {
	account := service.Session().GetUser(ctx)
	fmt.Println(account)
	if account == nil {
		return gerror.New(`Please login first`)
	}
	return dao.Account.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		_, err = dao.Company.Ctx(ctx).Data(g.Map{
			"name" : in.Name,
			"description" : in.Description,
			"industry" : in.Industry,
			"tag" : in.Tag,
			"address" : in.Address,
			"website" : in.Website,
			"city" : in.City,
			"size" : in.Size,
			"contact" : in.Contact,
			"logo" : in.Logo,
		}).Where("id", in.Company_id).Update()
		return err
	})
}

// Create creates user account.
func (s *sUser) ResetPassword(ctx context.Context, in *v1.ResetReq) (err error) {
	return dao.Account.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		_, err = dao.Account.Ctx(ctx).Data(do.Account{
			Password: in.Password,
		}).Where("email", in.Email).Update()
		return err
	})
}

// IsSignedIn checks and returns whether current user is already signed-in.
func (s *sUser) IsSignedIn(ctx context.Context) bool {
	if v := service.BizCtx().Get(ctx); v != nil && v.User != nil {
		return true
	}
	return false
}

// SignIn creates session for given user account.
func (s *sUser) SignIn(ctx context.Context, in model.UserSignInInput) (err error) {
	var user *entity.Account
	err = dao.Account.Ctx(ctx).Where(do.User{
		Email: in.Email,
		Password: in.Password,
	}).Scan(&user)
	if err != nil {
		return err
	}
	if user == nil {
		return gerror.New(`Email or Password not correct`)
	}
	if err = service.Session().SetUser(ctx, user); err != nil {
		return err
	}
	service.BizCtx().SetUser(ctx, &model.ContextUser{
		Id:       user.Id,
		Email: user.Email,
	})
	return nil
}

// SignOut removes the session for current signed-in user.
func (s *sUser) SignOut(ctx context.Context) error {
	return service.Session().RemoveUser(ctx)
}

// IsPassportAvailable checks and returns given Email is available for signing up.
func (s *sUser) IsPassportAvailable(ctx context.Context, Email string) (bool, error) {
	count, err := dao.Account.Ctx(ctx).Where(do.User{
		Email: Email,
	}).Count()
	if err != nil {
		return false, err
	}
	return count == 0, nil
}

// GetProfile retrieves and returns current user info in session.
func (s *sUser) GetUser(ctx context.Context) *entity.User {
	var account *entity.Account
	account = service.Session().GetUser(ctx)
	fmt.Println(account)
	if account == nil {
		return nil
	}
	var user *entity.User
	err := dao.User.Ctx(ctx).Where("account=?", account.Id).Scan(&user)
	fmt.Println(err)
	return user
}

// GetProfile retrieves and returns current user info in session.
func (s *sUser) GetUserSubscription(ctx context.Context) *entity.Subscription {
	var account *entity.Account
	account = service.Session().GetUser(ctx)
	fmt.Println(account)
	if account == nil {
		return nil
	}
	var user *entity.Subscription
	err := dao.UserSubscription.Ctx(ctx).Where("user_id=?", account.Id).Scan(&user)
	fmt.Println(err)
	return user
}

// GetProfile retrieves and returns current user info in session.
func (s *sUser) GetCompany(ctx context.Context, id uuid.UUID) *entity.Company {
	var company *entity.Company
	err := dao.Company.Ctx(ctx).Where("id=?", id).Scan(&company)
	fmt.Println(err)
	return company
}

// GetProfile retrieves and returns current user info in session.
func (s *sUser) GetProfile(ctx context.Context) *entity.Account {
	return service.Session().GetUser(ctx)
}

// GetProfile retrieves and returns current user info in session.
func (s *sUser) GetList(ctx context.Context) []*entity.User {
	var user []*entity.User
	err := dao.User.Ctx(ctx).Where("id >=?", 1).Limit(0, 10).Scan(&user)
	fmt.Println(user)
	fmt.Println(err)
	return user
}

// 备份 checks and returns whether current user is already signed-in.
func (s *sUser) Login(ctx context.Context, in model.UserSignInInput) (string, error) {
	var user *entity.User
	err := dao.User.Ctx(ctx).Where(do.User{
		Email: in.Email,
		Password: in.Password,
	}).Scan(&user)
	if err != nil {
		return "", err
	}
	if user == nil {
		return "", gerror.New(`Email or Password not correct`)
	}
	return "", err
}